
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#define WORD 40
#define HEXWORD 10
#define READSIZE 20

struct palavra {
    unsigned long int p : 40;
};

struct palavra convertInstruction(char * linha) {
    struct palavra p;
    // Inicia com a instrução exit
    p.p = 0;
    if (strcmp(linha, "EXIT\n") == 0)
        p.p = 0;
    else if (strcmp(linha, "LSH\n") == 0)
        p.p = 0x14000;
    else if (strcmp(linha, "RSH\n") == 0)
        p.p = 0x15000;
    else if (strcmp(linha, "LOAD MQ\n") == 0)
        p.p = 0x0A000;
    else {
        if (strstr(linha, "LOAD") != NULL)
            if (strstr(linha, "MQ") != NULL)
                //LOAD MQ,M(X)
                p.p = 0x09000;
            else if (strstr(linha, "-M") != NULL)
                //LOAD -M(X)
                p.p = 0x02000;
            else if (strstr(linha, "-|") != NULL)
                //LOAD -|M(X)|
                p.p = 0x04000;
            else if (strstr(linha, "|M") != NULL)
                //LOAD |M(X)|
                p.p = 0x03000;
            else
                //LOAD M(X)
                p.p = 0x01000;
        else if (strstr(linha, "ADD M") != NULL)
            //ADD M(X)
            p.p = 0x05000;
        else if (strstr(linha, "ADD |") != NULL)
            //ADD |M(X)|
            p.p = 0x07000;
        else if (strstr(linha, "SUB M") != NULL)
            //SUB M(X)
            p.p = 0x06000;
        else if (strstr(linha, "SUB |") != NULL)
            //SUB |M(X)|
            p.p = 0x08000;
        else if (strstr(linha, "MUL") != NULL)
            //MUL M(X)
            p.p = 0x0B000;
        else if (strstr(linha, "DIV") != NULL)
            //DIV M(X)
            p.p = 0x0C000;
        else if (strstr(linha, "STOR") != NULL)
            if (strchr(linha, ',') == NULL)
                //STOR M(X)
                p.p = 0x21000;
            else if (strstr(linha, "8:19") != NULL)
                //STOR M(X,8:19)
                p.p = 0x12000;
            else
                //STOR M(X,28,39)
                p.p = 0x13000;
        else if (strchr(linha, '+') != NULL)
            if (strstr(linha, "0:19") != NULL)
                //JUMP+ M(X,0:19)
                p.p = 0x0F000;
            else
                //JUMP+ M(X,20:39)
                p.p = 0x10000;
        else if (strstr(linha, "0:19") != NULL)
            //JUMP M(0:19)
            p.p = 0x0D000;
        else
            //JUMP M(20,39)
            p.p = 0x0E000;
        //CALCULA ENDEREÇO
        char * aux = strchr(linha, '(') + 1;
        char * snum = (char *) malloc(5);
        int i = 0;
        while (*aux != ',' && *aux != ')') {
            snum[i++] = *aux;
            aux++;
        }
        snum[i] = '\0';
        int inum = atoi(snum);
        p.p += inum;
    }
    return p;
}

int main(int argc, char** argv) {
    if (argc == 1) {
        printf("Erro: Falta nome do programa IAS como argumento!\n");
        exit(EXIT_FAILURE);
    }
    char * filename = argv[1];        
    char * path = malloc(sizeof (filename));
    strcpy(path, filename);
    
    FILE * ias = fopen(path, "r");
    if (ias == NULL) {
        fprintf(stderr, "Erro ao abrir o arquivo %s!\n", path);
        exit(EXIT_FAILURE);
    }

    strcpy(strchr(path,'.'),".txt");
    
    FILE * txt = fopen(path, "w+");
    if (txt == NULL) {
        printf("Erro ao criar o arquivo de saida: %s!\n", path);
        exit(EXIT_FAILURE);
    }

    strcpy(strchr(path,'.'),".hex");

    FILE *hex = fopen(path, "w+b");
    if (hex == NULL) {
        printf("Erro ao criar o arquivo de saida: %s!\n", path);
        exit(EXIT_FAILURE);
    }
    
    char * linha = (char *) malloc(READSIZE);
    struct palavra p;
    int inst = 1;
    while (!feof(ias)) {
        p.p = 0;
        if (inst) {
            fgets(linha, READSIZE, ias);
            p = convertInstruction(linha);
            p.p <<= 20;
            if (strstr(linha, "EXIT") == NULL) {
                fgets(linha, READSIZE, ias);
                p.p += convertInstruction(linha).p;
                if (strstr(linha, "EXIT") != NULL)
                    inst = 0;
            } else
                inst = 0;
        } else {
            fgets(linha, READSIZE, ias);
            long int inum = atol(linha);
            if (inum < 0) {
                p.p = 0x8000000000;
            }
            p.p += labs(inum);
        }
        struct palavra * ptr = &p;
        int numescritos = fwrite(ptr, sizeof (p), 1, hex);
        if (!numescritos && feof(ias)) {
            printf("Erro ao escrever no arquivo de saída!\n");
        }
        fprintf(txt, "%010lX\n", p.p);
    }
    fclose(ias);
    fclose(txt);
    free(linha);
    fclose(hex);   
    printf("Traduzido com sucesso para %s!\n", path);
    free(path);
    return 0;
}


